package openase.audio.fingerprinthash;

import openase.dsp.FrequencyDomain;

import org.apache.commons.math.complex.Complex;


public class DefaultFingerprintHashGenerator extends FingerprintHashGenerator {

	public static final FingerprintHashGenerator INSTANCE = new DefaultFingerprintHashGenerator();
	
	private DefaultFingerprintHashGenerator() {
	}

	private static final int LOWER_LIMIT = 0;
	private static final int UPPER_LIMIT = 180;
	private static final int[] RANGE = new int[] { 40, 80, 120, UPPER_LIMIT };
	private static final int AMOUNT_OF_POINTS = RANGE.length;
	
	@Override
	public long generate(FrequencyDomain fd) {
		Complex[] frequencies = fd.values();
		double[] highscores = new double[AMOUNT_OF_POINTS];
		int[] recordPoints = new int[AMOUNT_OF_POINTS];
		int freqRange = 0;
		for (int freq = LOWER_LIMIT; freq <= UPPER_LIMIT; freq++) {
			// Get the magnitude: (http://en.wikipedia.org/wiki/Magnitude_(mathematics)#Complex_numbers)
			// Others: (http://en.wikipedia.org/wiki/Magnitude_(mathematics)#Practical_math)
			if (RANGE[freqRange] < freq) {
				freqRange++;
			}
			double magnitude = frequencies[freq].abs();
			// Save the highest magnitude and corresponding frequency:
			if (magnitude > highscores[freqRange]) {
				highscores[freqRange] = magnitude;
				recordPoints[freqRange] = freq;
			}
		}
		return hash(recordPoints);
	}
	
	private static long hash(int[] p) {
		// & 0xFE to ignore the least significant bit
		int p0 = (RANGE[0] - p[0]) & 0xFE;
		int p1 = (RANGE[1] - p[1]) & 0xFE;
		int p2 = (RANGE[2] - p[2]) & 0xFE;
		int p3 = (RANGE[3] - p[3]) & 0xFE;

		return (p0) | ((p1) << 8) | ((p2) << 16) | ((p3) << 24);
	}

}
